package com.ruoyi.app.service.impl

import cn.hutool.core.date.DateUtil
import cn.hutool.core.util.ObjectUtil
import cn.hutool.core.util.PhoneUtil
import cn.hutool.core.util.RandomUtil
import cn.hutool.http.HttpUtil
import com.alibaba.fastjson.JSON
import com.aliyuncs.DefaultAcsClient
import com.aliyuncs.dypnsapi.model.v20170525.GetMobileRequest
import com.aliyuncs.profile.DefaultProfile
import com.baomidou.mybatisplus.extension.kotlin.KtQueryWrapper
import com.baomidou.shaun.core.mgt.SecurityManager
import com.baomidou.shaun.core.profile.TokenProfile
import com.ruoyi.app.common.*
import com.ruoyi.app.domain.dto.*
import com.ruoyi.app.domain.vo.QqLoginResult
import com.ruoyi.app.domain.vo.WxLoginResult
import com.ruoyi.app.service.LoginApiService
import com.ruoyi.back.domain.AppInfo
import com.ruoyi.back.domain.AppUser
import com.ruoyi.back.domain.dto.AppUserDto
import com.ruoyi.back.enums.LoginTypeEnum
import com.ruoyi.back.service.AppInfoService
import com.ruoyi.back.service.AppUserService
import com.ruoyi.common.core.redis.RedisCache
import com.ruoyi.config.AliSms
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service
import java.util.*
import java.util.concurrent.TimeUnit

@Service
class LoginApiServiceImpl : LoginApiService {

    @Autowired
    private lateinit var appUserService: AppUserService

    @Autowired
    private lateinit var securityManager: SecurityManager

    @Autowired
    private lateinit var redisCache: RedisCache

    @Autowired
    private lateinit var appInfoService: AppInfoService

    @Autowired
    private lateinit var aliSms: AliSms

    override fun register(registerDto: RegisterDto): Data<String> =
        appUserService.getOne(
            KtQueryWrapper(AppUser::class.java)
                .eq(AppUser::username, registerDto.phone)
                .eq(AppUser::loginType, LoginTypeEnum.PHONE.code)
        )
            ?.run {
                Fail(203, "手机号已经注册过")
            }
            ?: kotlin.run {
                redisCache.getCacheObject<String>(messageRedisKey(registerDto.phone!!))?.run {
                    ObjectUtil.equals(this, registerDto.code).takeIf { it }?.run {
                        Ok("手机号注册成功", kotlin.run {
                            val appUser = AppUser()
                            appUserService.save(
                                appUser.apply {
                                    username = registerDto.phone
                                    source = registerDto.source
                                    loginType = LoginTypeEnum.PHONE.code
                                    password = registerDto.password
                                    headUrl = "https://shuiyin-program.oss-cn-hangzhou.aliyuncs.com//userfiles/20221202145036.png"
                                    userId = RandomUtil.randomNumbers(6)
                                    registerDate = Date()
                                    lastLoginDate = Date()
                                }
                            )
                            appUser
                        }.run { tokenGenerator(id!!.toString()) })
                    } ?: run { Fail(201, "短信验证码不一致!") }
                } ?: kotlin.run { Fail(202, "短信验证码已经失效") }
            }

    override fun passwordLogin(phonePasswordLoginDto: PhonePasswordLoginDto): Data<String> =
        appUserService.getOne(
            KtQueryWrapper(AppUser::class.java).eq(AppUser::username, phonePasswordLoginDto.phone)
                .eq(AppUser::loginType, LoginTypeEnum.PHONE.code)
        )
            ?.let {
                return if (it.password == phonePasswordLoginDto.password) Ok(
                    "登录成功",
                    kotlin.run {
                        appUserService.updateById(it.apply {
                            phonePasswordLoginDto.source?.run {
                                source = phonePasswordLoginDto.source
                            }
                            lastLoginDate = DateUtil.date()
                        })
                        tokenGenerator(it.id!!.toString())
                    }
                )
                else Fail(205, "密码不一致!")
            } ?: Fail(204, "该手机号尚未注册!")

    override fun forgetPassword(registerDto: RegisterDto): Data<Boolean> =
        appUserService.getOne(
            KtQueryWrapper(AppUser::class.java)
                .eq(AppUser::username, registerDto.phone)
                .eq(AppUser::loginType, LoginTypeEnum.PHONE.code)
        )?.let {
            redisCache.getCacheObject<String>(messageRedisKey(registerDto.phone!!))?.run {
                ObjectUtil.equals(this, registerDto.code).takeIf { it }?.run {
                    Ok("修改密码成功", kotlin.run {
                        appUserService.updateById(it.apply {
                            password = registerDto.password
                        })
                    })
                } ?: run { Fail(201, "短信验证码不一致!") }
            } ?: kotlin.run { Fail(202, "短信验证码已经失效") }
        } ?: Fail(204, "该手机号尚未注册!")

    override fun threeLogin(threeLoginDto: ThreeLoginDto): Data<String> =
        when (threeLoginDto.loginType) {
            1 ->
                HttpUtil.get(weixinInfoUrl(threeLoginDto.access_token!!, threeLoginDto.openid!!)).let { result ->
                    JSON.parseObject(result, WxLoginResult::class.java).run {
                        if (errmsg == null) Ok("微信登陆成功", appUserService.operationUser(
                            AppUserDto(
                                username = nickname,
                                headUrl = headimgurl,
                                loginType = LoginTypeEnum.WEI_XIN.code,
                                source = threeLoginDto.source,
                                openId = this.openid
                            )
                        ).run { tokenGenerator(id!!.toString()) })
                        else Fail(errmsg!!)
                    }
                }
            else -> HttpUtil.get(qqInfoUrl(threeLoginDto.access_token!!, threeLoginDto.openid!!)).let { result ->
                JSON.parseObject(result, QqLoginResult::class.java).run {
                    if (ret == 0) Ok("qq登陆成功", appUserService.operationUser(
                        AppUserDto(
                            username = nickname,
                            headUrl = figureurl_qq_1,
                            loginType = LoginTypeEnum.QQ.code,
                            source = threeLoginDto.source,
                            openId = threeLoginDto.openid
                        )
                    ).run { tokenGenerator(id!!.toString()) })
                    else Fail(msg!!)
                }
            }
        }



    override fun phoneLogin(phoneLoginDto: PhoneLoginDto): Data<String> =
        redisCache.getCacheObject<String>(messageRedisKey(phoneLoginDto.phone))?.run {
            ObjectUtil.equals(this, phoneLoginDto.code).takeIf { it }?.run {
                appUserService.getOne(
                    KtQueryWrapper(AppUser::class.java).eq(AppUser::username, phoneLoginDto.phone)
                        .eq(AppUser::loginType, LoginTypeEnum.PHONE.code)
                )
                    ?.run {
                        Ok("手机号登录成功", tokenGenerator(id!!.toString()))
                    } ?: Fail(204, "手机号尚未注册")
            } ?: run { Fail(201, "短信验证码不一致!") }
        } ?: kotlin.run { Fail(202, "短信验证码已经失效") }

    override fun oneKeyLogin(oneKeyLoginDto: OneKeyLoginDto): Data<String> =
        DefaultProfile.getProfile("cn-shanghai", "LTAI5tRQ1acQfyPAnkCWvMAd", "SVVk0Non9jDhpSdISorUnfYZFBqs9c")
            .run {
                DefaultAcsClient(this).getAcsResponse(GetMobileRequest().apply { accessToken = oneKeyLoginDto.token })
                    .let { response ->

                        response.code.takeIf { it == "OK" }?.run {
                            val mobile = response.getMobileResultDTO.mobile
                            appUserService.getOne(
                                KtQueryWrapper(AppUser::class.java).eq(AppUser::username, mobile)
                            )?.run {
                                Ok("手机号一键登陆成功", tokenGenerator(id!!.toString()))
                            } ?: kotlin.run {
                                Ok("手机号一键登录成功", appUserService.operationUser(
                                    AppUserDto(
                                        username = mobile,
                                        source = oneKeyLoginDto.source,
                                        loginType = LoginTypeEnum.PHONE.code,
                                    )
                                ).run { tokenGenerator(id!!.toString()) })
                            }
                        } ?: Fail(response.message)
                    }
            }


    override fun sendSms(phone: String): Data<String> =
        if (PhoneUtil.isPhone(phone)) {
            aliSms.send(phone).also {
                redisCache.setCacheObject(messageRedisKey(phone), it, 5, TimeUnit.MINUTES)
            }
            Ok("发送短信验证码成功")
        } else Fail("传入正确格式手机号")


    override fun getUserAgreement(): Data<String?> =
        appInfoService.getOne(
            KtQueryWrapper(AppInfo::class.java)
                .eq(AppInfo::type, 1)
                .orderByDesc(AppInfo::createTime)
                .last("limit 1")
        )
            ?.run { Ok("获取用户协议成功", text) }
            ?: Ok("暂无数据", null)

    override fun getPrivacyPolicy(): Data<String?> =
        appInfoService.getOne(
            KtQueryWrapper(AppInfo::class.java)
                .eq(AppInfo::type, 2)
                .orderByDesc(AppInfo::createTime)
                .last("limit 1")
        )
            ?.run { Ok("获取隐私政策成功", text) }
            ?: Ok("暂无数据", null)

    /**
     * 通用token构建器
     */
    private val tokenGenerator: (String) -> String = {
        securityManager.login(TokenProfile().apply { id = it })
    }

}